import { EventEmitter } from 'events';
import { PluginInterface } from './defined/plugins';
import { Logger } from '../logger';

/**
 * 插件生命周期事件
 */
export enum PluginLifecycleEvent {
  BEFORE_LOAD = 'beforeLoad',
  AFTER_LOAD = 'afterLoad',
  BEFORE_ENABLE = 'beforeEnable',
  AFTER_ENABLE = 'afterEnable',
  BEFORE_DISABLE = 'beforeDisable',
  AFTER_DISABLE = 'afterDisable',
  BEFORE_UNLOAD = 'beforeUnload',
  AFTER_UNLOAD = 'afterUnload',
  ERROR = 'error'
}

/**
 * 插件状态
 */
export enum PluginState {
  UNLOADED = 'unloaded',
  LOADING = 'loading',
  LOADED = 'loaded',
  ENABLING = 'enabling',
  ENABLED = 'enabled',
  DISABLING = 'disabling',
  DISABLED = 'disabled',
  ERROR = 'error'
}

/**
 * 插件生命周期管理器
 */
export class PluginLifecycleManager extends EventEmitter {
  private pluginStates: Map<string, PluginState> = new Map();
  private pluginLoadTimes: Map<string, number> = new Map();
  private pluginErrors: Map<string, Error[]> = new Map();

  /**
   * 获取插件状态
   */
  getPluginState(pluginId: string): PluginState {
    return this.pluginStates.get(pluginId) || PluginState.UNLOADED;
  }

  /**
   * 设置插件状态
   */
  setPluginState(pluginId: string, state: PluginState): void {
    const oldState = this.pluginStates.get(pluginId);
    this.pluginStates.set(pluginId, state);
    
    Logger.info(`Plugin ${pluginId} state changed: ${oldState} -> ${state}`);
    this.emit('stateChanged', pluginId, state, oldState);
  }

  /**
   * 记录插件加载时间
   */
  recordLoadTime(pluginId: string, loadTime: number): void {
    this.pluginLoadTimes.set(pluginId, loadTime);
    Logger.debug(`Plugin ${pluginId} load time: ${loadTime}ms`);
  }

  /**
   * 获取插件加载时间
   */
  getLoadTime(pluginId: string): number | undefined {
    return this.pluginLoadTimes.get(pluginId);
  }

  /**
   * 记录插件错误
   */
  recordError(pluginId: string, error: Error): void {
    if (!this.pluginErrors.has(pluginId)) {
      this.pluginErrors.set(pluginId, []);
    }
    this.pluginErrors.get(pluginId)!.push(error);
    
    Logger.error(`Plugin ${pluginId} error:`, error);
    this.emit(PluginLifecycleEvent.ERROR, pluginId, error);
  }

  /**
   * 获取插件错误历史
   */
  getErrors(pluginId: string): Error[] {
    return this.pluginErrors.get(pluginId) || [];
  }

  /**
   * 清除插件错误历史
   */
  clearErrors(pluginId: string): void {
    this.pluginErrors.delete(pluginId);
  }

  /**
   * 执行生命周期钩子
   */
  async executeLifecycleHook(
    event: PluginLifecycleEvent,
    pluginId: string,
    plugin?: PluginInterface,
    ...args: any[]
  ): Promise<void> {
    try {
      this.emit(event, pluginId, plugin, ...args);
      
      // 如果插件实现了生命周期钩子，则调用
      if (plugin && plugin.prototype) {
        const hookName = `on${event.charAt(0).toUpperCase() + event.slice(1)}`;
        const hook = (plugin.prototype as any)[hookName];
        if (typeof hook === 'function') {
          await hook.call(plugin.prototype, ...args);
        }
      }
    } catch (error) {
      this.recordError(pluginId, error as Error);
      throw error;
    }
  }

  /**
   * 获取所有插件状态统计
   */
  getStatsSnapshot(): {
    states: Record<PluginState, number>;
    totalPlugins: number;
    averageLoadTime: number;
    totalErrors: number;
    } {
    const states: Record<PluginState, number> = {
      [PluginState.UNLOADED]: 0,
      [PluginState.LOADING]: 0,
      [PluginState.LOADED]: 0,
      [PluginState.ENABLING]: 0,
      [PluginState.ENABLED]: 0,
      [PluginState.DISABLING]: 0,
      [PluginState.DISABLED]: 0,
      [PluginState.ERROR]: 0,
    };

    for (const state of this.pluginStates.values()) {
      states[state]++;
    }

    const loadTimes = Array.from(this.pluginLoadTimes.values());
    const averageLoadTime = loadTimes.length > 0 
      ? loadTimes.reduce((sum, time) => sum + time, 0) / loadTimes.length 
      : 0;

    const totalErrors = Array.from(this.pluginErrors.values())
      .reduce((sum, errors) => sum + errors.length, 0);

    return {
      states,
      totalPlugins: this.pluginStates.size,
      averageLoadTime,
      totalErrors,
    };
  }

  /**
   * 清理插件数据
   */
  cleanup(pluginId: string): void {
    this.pluginStates.delete(pluginId);
    this.pluginLoadTimes.delete(pluginId);
    this.pluginErrors.delete(pluginId);
  }
}